package com.jess.arms.di.module;

import android.app.Application;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;

import com.blankj.utilcode.util.SPUtils;
import com.google.gson.GsonBuilder;
import com.jess.arms.base.delegate.AppLifecycles;
import com.jess.arms.base.delegate.sys.LoginStateUtil;
import com.jess.arms.base.delegate.sys.SysInfo;
import com.jess.arms.database.MMkvHelper;
import com.jess.arms.di.module.AppModule;
import com.jess.arms.di.module.ClientModule;
import com.jess.arms.di.module.GlobalConfigModule;
import com.jess.arms.http.log.RequestInterceptor;
import com.jess.arms.integration.ConfigModule;
import com.orhanobut.logger.Logger;
import com.tencent.mmkv.MMKV;
import com.tencent.mmkv.MMKVHandler;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.rx_cache2.internal.RxCache;
import okhttp3.CacheControl;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;

/**
 * ================================================
 * App 的全局配置信息在此配置, 需要将此实现类声明到 AndroidManifest 中
 * ConfigModule 的实现类可以有无数多个, 在 Application 中只是注册回调, 并不会影响性能 (多个 ConfigModule 在多 Module 环境下尤为受用)
 *
 * @see com.jess.arms.base.delegate.AppDelegate
 * @see com.jess.arms.integration.ManifestParser
 * @see <a href="https://github.com/JessYanCoding/MVPArms/wiki">请配合官方 Wiki 文档学习本框架</a>
 * @see <a href="https://github.com/JessYanCoding/MVPArms/wiki/UpdateLog">更新日志, 升级必看!</a>
 * @see <a href="https://github.com/JessYanCoding/MVPArms/wiki/Issues">常见 Issues, 踩坑必看!</a>
 * @see <a href="https://github.com/JessYanCoding/ArmsComponent/wiki">MVPArms 官方组件化方案 ArmsComponent, 进阶指南!</a>
 * Created by MVPArmsTemplate on 01/07/2019 17:36
 * <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>MMkvHelper
 * <a href="https://github.com/JessYanCoding">Follow me</a>
 * ================================================
 */
public final class GlobalConfiguration implements ConfigModule {
    //    public static String sDomain = Api.APP_DOMAIN;

    @Override
    public void applyOptions(Context context, GlobalConfigModule.Builder builder) {
        //  类似于Logger库的打印，不适合列表的打印
//        if (!BuildConfig.LOG_DEBUG) { //Release 时, 让框架不再打印 Http 请求和响应的信息
        builder.printHttpLogLevel(RequestInterceptor.Level.NONE);
//        }
        builder.printHttpLogLevel(RequestInterceptor.Level.NONE);

        MMKV.initialize(context);
        MMKV mmkv=MMKV.defaultMMKV();
        String baseUrl = mmkv.getString("baseUrl", "http://139.9.246.226:8088/");
        builder.baseurl(baseUrl)
                //强烈建议自己自定义图片加载逻辑, 因为 arms-imageloader-glide 提供的 GlideImageLoaderStrategy 并不能满足复杂的需求
                //请参考 https://github.com/JessYanCoding/MVPArms/wiki#3.4
                .imageLoaderStrategy(null)
//                .imageLoaderStrategy(new GlideImageLoaderStrategy())

                //想支持多 BaseUrl, 以及运行时动态切换任意一个 BaseUrl, 请使用 https://github.com/JessYanCoding/RetrofitUrlManager
                //如果 BaseUrl 在 App 启动时不能确定, 需要请求服务器接口动态获取, 请使用以下代码
                //以下方式是 Arms 框架自带的切换 BaseUrl 的方式, 在整个 App 生命周期内只能切换一次, 若需要无限次的切换 BaseUrl, 以及各种复杂的应用场景还是需要使用 RetrofitUrlManager 框架
                //以下代码只是配置, 还要使用 Okhttp (AppComponent 中提供) 请求服务器获取到正确的 BaseUrl 后赋值给 GlobalConfiguration.sDomain
                //切记整个过程必须在第一次调用 Retrofit 接口之前完成, 如果已经调用过 Retrofit 接口, 此种方式将不能切换 BaseUrl
                //                .baseurl(new BaseUrl() {
                //                    @Override
                //                    public HttpUrl url() {
                //                        return HttpUrl.parse(sDomain);
                //                    }
                //                })

                //可根据当前项目的情况以及环境为框架某些部件提供自定义的缓存策略, 具有强大的扩展性
                //                .cacheFactory(new Cache.Factory() {
                //                    @NonNull
                //                    @Override
                //                    public Cache build(CacheType type) {
                //                        switch (type.getCacheTypeId()){
                //                            case CacheType.EXTRAS_TYPE_ID:
                //                                return new IntelligentCache(500);
                //                            case CacheType.CACHE_SERVICE_CACHE_TYPE_ID:
                //                                return new Cache(type.calculateCacheSize(context));//自定义 Cache
                //                            default:
                //                                return new LruCache(200);
                //                        }
                //                    }
                //                })

                //若觉得框架默认的打印格式并不能满足自己的需求, 可自行扩展自己理想的打印格式 (以下只是简单实现)
                //                .formatPrinter(new FormatPrinter() {
                //                    @Override
                //                    public void printJsonRequest(Request request, String bodyString) {
                //                        Timber.i("printJsonRequest:" + bodyString);
                //                    }
                //
                //                    @Override
                //                    public void printFileRequest(Request request) {
                //                        Timber.i("printFileRequest:" + request.url().toString());
                //                    }
                //
                //                    @Override
                //                    public void printJsonResponse(long chainMs, boolean isSuccessful, int code,
                //                                                  String headers, MediaType contentType, String bodyString,
                //                                                  List<String> segments, String message, String responseUrl) {
                //                        Timber.i("printJsonResponse:" + bodyString);
                //                    }
                //
                //                    @Override
                //                    public void printFileResponse(long chainMs, boolean isSuccessful, int code, String headers,
                //                                                  List<String> segments, String message, String responseUrl) {
                //                        Timber.i("printFileResponse:" + responseUrl);
                //                    }
                //                })

                //可以自定义一个单例的线程池供全局使用
                //                .executorService(Executors.newCachedThreadPool())

                //这里提供一个全局处理 Http 请求和响应结果的处理类, 可以比客户端提前一步拿到服务器返回的结果, 可以做一些操作, 比如 Token 超时后, 重新获取 Token
                .globalHttpHandler(new GlobalHttpHandlerImpl(context))
                //用来处理 RxJava 中发生的所有错误, RxJava 中发生的每个错误都会回调此接口
                //RxJava 必须要使用 ErrorHandleSubscriber (默认实现 Subscriber 的 onError 方法), 此监听才生效
                .responseErrorListener(new ResponseErrorListenerImpl()).gsonConfiguration(new AppModule.GsonConfiguration() {
            @Override
            public void configGson(@NonNull Context context, @NonNull GsonBuilder gsonBuilder) {//这里可以自己自定义配置 Gson 的参数
                gsonBuilder.serializeNulls()//支持序列化值为 null 的参数
                        .enableComplexMapKeySerialization();//支持将序列化 key 为 Object 的 Map, 默认只能序列化 key 为 String 的 Map
            }
        }).retrofitConfiguration(new ClientModule.RetrofitConfiguration() {
            @Override
            public void configRetrofit(@NonNull Context context, @NonNull Retrofit.Builder retrofitBuilder) {//这里可以自己自定义配置 Retrofit 的参数, 甚至您可以替换框架配置好的 OkHttpClient 对象 (但是不建议这样做, 这样做您将损失框架提供的很多功能)
                //                                                retrofitBuilder.addConverterFactory(FastJsonConverterFactory.create());//比如使用 FastJson 替代 Gson
                retrofitBuilder.addConverterFactory(new NullOnEmptyConverterFactory());
            }
        }).okhttpConfiguration(new ClientModule.OkhttpConfiguration() {
            @Override
            public void configOkhttp(@NonNull Context context, @NonNull OkHttpClient.Builder okhttpBuilder) {
                //                    okhttpBuilder.sslSocketFactory(); //支持 Https, 详情请百度
                okhttpBuilder.writeTimeout(30, TimeUnit.SECONDS);
                okhttpBuilder.connectTimeout(30, TimeUnit.SECONDS);
                okhttpBuilder.readTimeout(30, TimeUnit.SECONDS);
                okhttpBuilder.addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {

                        CacheControl cacheControl = new CacheControl.Builder().build();
                        //不使用缓存
                        Request.Builder builder = chain.request().newBuilder().cacheControl(cacheControl);
                        Request request=null;
                                request = builder.url(chain.request().url().toString()).cacheControl(cacheControl)
                                        .build();
                        Response response=chain.proceed(request==null?builder.build():request);

                        return GlobalHttpHandlerImpl.getInstance().onHttpResultResponse("",chain,response);

                    }
                });
                okhttpBuilder.followRedirects(false);
                okhttpBuilder.followSslRedirects(false);
                //session保持，保存Cookie值
                okhttpBuilder.cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {

                        if(SysInfo.cookieStore.get(url.host())==null||SysInfo.cookieStore.get(url.host()).size()==0){
                            SysInfo.cookieStore.put(url.host(), cookies);
                            LoginStateUtil.cacheOkhttpCookie(SysInfo.cookieStore);
                        }
                    }

                    @Override
                    public List<Cookie> loadForRequest(HttpUrl url) {
                        synchronized (SysInfo.class){
                            List<Cookie> cookies = SysInfo.cookieStore.get(url.host());
                            return cookies != null ? cookies : new ArrayList<Cookie>();
                        }

                    }
                });
                //打印日志，使用OKHttp的日志库
                okhttpBuilder.addInterceptor(getHttpLoggingInterceptor());
                //使用一行代码监听 Retrofit／Okhttp 上传下载进度监听, 以及 Glide 加载进度监听, 详细使用方法请查看 https://github.com/JessYanCoding/ProgressManager
//                ProgressManager.getInstance().with(okhttpBuilder);
                //让 Retrofit 同时支持多个 BaseUrl 以及动态改变 BaseUrl, 详细使用方法请查看 https://github.com/JessYanCoding/RetrofitUrlManager
                //                    RetrofitUrlManager.getInstance().with(okhttpBuilder);
            }
        }).rxCacheConfiguration(new ClientModule.RxCacheConfiguration() {
            @Override
            public RxCache configRxCache(@NonNull Context context, @NonNull RxCache.Builder rxCacheBuilder) {//这里可以自己自定义配置 RxCache 的参数
                rxCacheBuilder.useExpiredDataIfLoaderNotAvailable(true);
                //想自定义 RxCache 的缓存文件夹或者解析方式, 如改成 FastJson, 请 return rxCacheBuilder.persistence(cacheDirectory, new FastJsonSpeaker());
                //否则请 return null;
                return null;
            }
        });
    }

    @Override
    public void injectAppLifecycle(Context context, List<AppLifecycles> lifecycles) {
        //AppLifecycles 中的所有方法都会在基类 Application 的对应生命周期中被调用, 所以在对应的方法中可以扩展一些自己需要的逻辑
        //可以根据不同的逻辑添加多个实现类
        lifecycles.add(new AppLifecyclesImpl());
    }

    @Override
    public void injectActivityLifecycle(Context context, List<Application.ActivityLifecycleCallbacks> lifecycles) {
        //ActivityLifecycleCallbacks 中的所有方法都会在 Activity (包括三方库) 的对应生命周期中被调用, 所以在对应的方法中可以扩展一些自己需要的逻辑
        //可以根据不同的逻辑添加多个实现类
        lifecycles.add(new ActivityLifecycleCallbacksImpl());
    }

    @Override
    public void injectFragmentLifecycle(Context context, List<FragmentManager.FragmentLifecycleCallbacks> lifecycles) {
        //FragmentLifecycleCallbacks 中的所有方法都会在 Fragment (包括三方库) 的对应生命周期中被调用, 所以在对应的方法中可以扩展一些自己需要的逻辑
        //可以根据不同的逻辑添加多个实现类
        lifecycles.add(new FragmentLifecycleCallbacksImpl());
    }

    /**
     * 日志输出
     * 自行判定是否添加
     *
     * @return
     */
    private HttpLoggingInterceptor getHttpLoggingInterceptor() {
        //日志显示级别
        HttpLoggingInterceptor.Level level = HttpLoggingInterceptor.Level.BODY;
        //新建log拦截器
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(level);
        return loggingInterceptor;
    }


}
